<?php
namespace app\index\controller;


/**
 * 用于检测业务代码死循环或者长时间阻塞等问题
 * 如果发现业务卡死，可以将下面declare打开（去掉//注释），并执行php start.php reload
 * 然后观察一段时间workerman.log看是否有process_timeout异常
 */
declare(ticks=1);

/**
 * 聊天主逻辑
 * 主要是处理 onMessage onClose 
 */
use \GatewayWorker\Lib\Gateway;
use Workerman\Lib\Timer;  
use think\Controller;

class Events  extends Controller
{
   /**
    * 有消息时
    * @param int $client_id
    * @param mixed $message
    */
   public static function onMessage($client_id, $message)
   {
        // debug
        echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']}  client_id:$client_id session:".json_encode($_SESSION)." onMessage:".$message."\n";
        
        // 客户端传递的是json数据
        $message_data = json_decode($message, true);
        if(!$message_data)
        {
            return ;
        }
        
        // 根据类型执行不同的业务
        switch($message_data['action'])
        {
            // 客户端回应服务端的心跳
            case 'pong':
                return;
            case 'match_succ':
                $room_id = $_SESSION['room_id']; 
                $grad_id = $room_id;//房间段位id
                $is_robot = !empty($message_data['is_robot'])?$message_data['is_robot']:0;
                //return Gateway::sendToGroup($room_id,json_encode(array_merge($message_data,Gateway::getAllClientSessions())));
                //
                //匹配用户pk
                //match_success
                $room_all_user = Gateway::getClientSessionsByGroup($room_id);
                $to_client_uid = 0;//Events::get_pk_user(array_keys($room_all_user),$client_id);

                if($to_client_uid==0){//获取机器人用户
                    if($is_robot){
                        //$user_info = db('user')->field('id,openid,avatar,display_name,sex,city,grad_name,count_wins,exp,is_robot')->where(['is_robot'=>1])->find();
                        //随机抽取机器人
                        $user_info = db('user')->field('id,openid,avatar,display_name,sex,city,grad_name,count_wins,exp,is_robot')->where(['is_robot'=>1])->order('rand()')->limit(1)->find();
                        if(!empty($user_info)){
                            $user_info['room_id'] = $room_id;
                            $user_info['client_name'] = $client_name = $user_info['display_name'];
                            $user_info['level'] = get_user_level($user_info['exp']);
                            $to_client_info = $user_info;
                            //Gateway::setSession($client_id,$user_info);
                        }else{
                            $to_client_info = [];
                        }
                    }else{
                        $to_client_info = [];
                    }
                }else{
                    $to_client_info = Gateway::getSession($to_client_uid);
                    if(empty($to_client_info))$to_client_info = [];
                }

                if(!empty($to_client_info)){//匹配成功后，离开该段位房间
                    if(!empty($client_id))Gateway::leaveGroup($client_id,$room_id);
                    if(!empty($to_client_uid))Gateway::leaveGroup($to_client_uid,$room_id);
                    //进入用户对战房间
                    $room_id =$_SESSION['room_id']= md5($client_id.$to_client_uid);
                    if(!empty($client_id))Gateway::joinGroup($client_id, $room_id);
                    if(!empty($to_client_uid))Gateway::joinGroup($to_client_uid, $room_id);
                }
                
                //
                $from_client_info = Gateway::getSession($client_id);
                $new_message = [
                    'action'=>'match_succ',
                    'client_uid'=>$message_data['client_uid'],
                    'match_status'=>($from_client_info && $to_client_info) ? 1:0,//1为匹配成功
                    'from_client_info'=>$from_client_info,
                    'to_client_info'=>$to_client_info,
                    'room_id'=>$room_id,//pk房间id
                    'aaaaaaa'=>Gateway::getClientSessionsByGroup($room_id),
                    'bbbbbb'=>$room_all_user
                ];
                if($new_message['match_status']==1){
                    $QuestionsModel = \think\Loader::model('QuestionsModel');
                    $params = [
                        'user_id'=>$from_client_info['id'],
                        'to_user_id'=>$to_client_info['id'],
                        'grad_id'=>$grad_id
                    ];
                    $QuestionsModel->deduct_points($params);//扣除用户参赛段位金币

                    $params = [
                        'is_auto_answer'=>$message_data['is_auto_answer'],
                        'grad_id'=>$grad_id,
                        'user_id'=>$from_client_info['id'],
                        'to_user_id'=>$to_client_info['id']
                    ];
                    $new_message['questions'] = $QuestionsModel->getQuestionsPk($params);

                    return Gateway::sendToGroup($room_id,json_encode($new_message));
                    //向对方用户发消息指令
                    //return Gateway::sendToClient($to_client_uid,json_encode($new_message));
                }
                return Gateway::sendToClient($client_id,json_encode($new_message));
                //return Gateway::sendToGroup($room_id,json_encode($new_message));
            case 'match_friends_succ'://发起者发起用户答题邀请1
                $room_id = $_SESSION['room_id']; 
                $is_sponsor = isset($message_data['is_sponsor'])?$message_data['is_sponsor']:0;//房主标志
                //
                //匹配用户pk
                $is_entry = \think\Cache::get($room_id.'is_entry');//参赛者 client_id
                $to_client_id = $message_data['to_client_id'];//房主
                $to_client_id = (!empty($is_sponsor) && !empty($is_entry) && $to_client_id==0) ?$message_data['client_uid']:$to_client_id;

                echo '8888888888888==='.$is_entry;
                $from_client_info = [];
                $wg_room_num = 0;//围观人数
                //\think\Cache::set($room_id.'is_entry','');    //测试清空缓存
                if(!empty($is_entry)){//0&&
                    $user_id = $is_entry;
                    $to_user_id = $to_client_id;

                    $data = self::get_friends_pk_user($room_id,$user_id,$to_user_id);//获取pk信息
                    $from_client_info = $data['from_client_info'];
                    $to_client_info = $data['to_client_info'];
                    //围观人数
                    $room_all_user = Gateway::getClientSessionsByGroup($room_id);
                    $wg_room_num = count($room_all_user) - 1;
                    
                }else{
                    $from_client_info = Gateway::getSession($client_id);
                    $user_info = db('user')->field('id,openid,avatar,display_name,sex,city,grad_name,count_wins,exp,is_robot')->where(['openid'=>$to_client_id])->find();
                    if(!empty($user_info)){
                        $user_info['room_id'] = $room_id;
                        $user_info['client_name'] = $user_info['display_name'];
                        $user_info['level'] = get_user_level($user_info['exp']);
                        $to_client_info = $user_info;
                    }else{
                        $to_client_info = [];
                    }
                }
                $new_message = [
                    'action'=>'match_friends_succ',
                    'client_uid'=>$message_data['client_uid'],
                    'match_status'=>($from_client_info && $to_client_info) ? 1:0,//1为匹配成功
                    'from_client_info'=>$from_client_info,
                    'to_client_info'=>$to_client_info,
                    'room_id'=>$room_id,//pk房间id
                    'is_sponsor'=>$is_sponsor,
                    'wg_room_num'=>$wg_room_num
                ];
                if($new_message['match_status']==1){
                    //$_SESSION['is_entry'] = $client_id;//参赛者
                    $is_entry = \think\Cache::get($room_id.'is_entry');
                    if(empty($is_entry) && empty($message_data['is_sponsor'])){
                        \think\Cache::set($room_id.'is_entry',$message_data['client_uid']);

                    }else{
                        
                    }
                    $new_message['is_entry'] = $is_entry?$is_entry:$message_data['client_uid'];
                    $QuestionsModel = \think\Loader::model('QuestionsModel');
                    $params = [
                        'is_auto_answer'=>$message_data['is_auto_answer'],
                        'user_id'=>$from_client_info['id'],
                        'to_user_id'=>$to_client_info['id']
                    ];

                    $new_message['questions'] = $QuestionsModel->getQuestionsPk($params);
                }
                return Gateway::sendToGroup($room_id,json_encode($new_message));

            case 'match_fpk_succ'://发起者确认双方答题开始2
                $room_id = $_SESSION['room_id']; 
                $new_message = [
                    'action'=>'match_fpk_succ',
                    'client_uid'=>$message_data['client_uid'],
                    //'type'=>$message_data['type'],
                ];

                return Gateway::sendToGroup($room_id,json_encode($new_message));
            case 'fpk_wg_succ'://用户观战状态
                $room_id = $_SESSION['room_id']; 
                $to_client_id = $room_id;//$message_data['to_client_id'];//房主
                $from_client_info = [];
                $to_client_info = [];
                $room_all_user = Gateway::getClientSessionsByGroup($room_id);
                $is_entry = \think\Cache::get($room_id.'is_entry');
                echo '99999999999'.$is_entry.'======'.$to_client_id."\n";
                if($message_data['type']==2 && $is_entry){
                    self::clear_entry_user($client_id,$room_id);
                    $user_id = $message_data['client_uid'];
                    $to_user_id = $to_client_id;
                    $data = self::get_friends_pk_user($room_id,$user_id,$to_user_id);//获取pk信息
                    //$from_client_info = $data['from_client_info'];
                    $to_client_info = $data['to_client_info'];
                }else if($message_data['type']==1 && !$is_entry){//参赛
                    $user_id = $to_client_id;
                    $to_user_id = $message_data['client_uid'];
                    $data = self::get_friends_pk_user($room_id,$user_id,$to_user_id);//获取pk信息
                    $from_client_info = $data['from_client_info'];
                    $to_client_info = $data['to_client_info'];
                    //重新设置参赛者标志
                    \think\Cache::set($room_id.'is_entry',$message_data['client_uid']);
                }
                $cs_num = 0;
                if(!empty($is_entry))$cs_num=1;
                $wg_room_num = count($room_all_user) - $cs_num;//围观人数
                if($wg_room_num == count($room_all_user))$wg_room_num=0;
                $is_entry = \think\Cache::get($room_id.'is_entry');
                $new_message = [
                    'action'=>'fpk_wg_succ',
                    'client_uid'=>$message_data['client_uid'],
                    'type'=>$message_data['type'],
                    'from_client_info'=>$from_client_info,
                    'to_client_info'=>$to_client_info,
                    'room_all_user'=>$room_all_user,
                    'wg_room_num'=>$wg_room_num,
                    'is_entry'=>$is_entry,
                    'room_id'=>$room_id,
                    //'is_self_entry'=>$is_entry==$client_id ? 1 : 0,//自己是否参赛者
                ];

                return Gateway::sendToGroup($room_id,json_encode($new_message));
            // 客户端登录 message格式: {type:login, name:xx, room_id:1} ，添加到客户端，广播给所有客户端xx进入聊天室
            case 'leave_group'://用户离开房间
                            
                $room_id = !empty($message_data['room_id'])?$message_data['room_id']:$_SESSION['room_id'];
                $type = !empty($message_data['type']) ? $message_data['type']:1;
                Gateway::leaveGroup($client_id,$room_id);
                if(!empty($message_data['is_sponsor'])){//房主离开的
                    \think\Cache::set($room_id.'is_entry','');
                }else{
                    self::clear_entry_user($client_id,$room_id);
                }
                

                $new_message = [
                    'action'=>'leave_group',
                    'client_uid'=>$message_data['client_uid'],
                    'type'=>$type
                ];
                echo '77777777'.$room_id;
                //$ckey = 'pk_'.$client_id;
                //\think\Cache::set($ckey,null);
                //
                return Gateway::sendToGroup($room_id,json_encode($new_message));
            case 'login':
                // 判断是否有房间号
                if(!isset($message_data['room_id']))
                {
                    throw new \Exception("\$message_data['room_id'] not set. client_ip:{$_SERVER['REMOTE_ADDR']} \$message:$message");
                }
                
                // 把房间号昵称放到session中
                $room_id = $message_data['room_id'];
                $client_uid = $message_data['client_uid'];//2018-02-07 10:37:51
                //$client_name = htmlspecialchars($message_data['client_name']);
                //$_SESSION['room_id'] = $room_id;
                //$_SESSION['client_name'] = $client_name;

                Gateway::bindUid($client_id, $client_uid);//将client_id 和 uid绑定
                //设置用户session信息 2018-02-23 10:27:09
                $user_info = db('user')->field('id,openid,avatar,display_name,sex,city,grad_name,count_wins,exp,is_robot')->where(['openid'=>$client_uid])->find();
                $user_info['room_id'] = $room_id;
                $user_info['client_name'] = $client_name = $user_info['display_name'];
                $user_info['level'] = get_user_level($user_info['exp']);
                Gateway::setSession($client_id,$user_info);
                /*$is_entry = \think\Cache::get($room_id.'is_entry');
                if($is_entry==$user_info['openid']){
                    \think\Cache::set($room_id.'is_entry','');
                }*/
                self::clear_entry_user($client_id,$room_id);

                // 获取房间内所有用户列表 
                $clients_list = Gateway::getClientSessionsByGroup($room_id);
                foreach($clients_list as $tmp_client_id=>$item)
                {
                    $clients_list[$tmp_client_id] = $item['client_name'];
                }
                $clients_list[$client_id] = $client_name;
                
                // 转播给当前房间的所有客户端，xx进入聊天室 message {type:login, client_id:xx, name:xx} 
                $is_entry = \think\Cache::get($room_id.'is_entry');
                $new_message = array(
                    'action'=>$message_data['action'], 
                    'client_id'=>$client_id,
                    'client_uid'=>$client_uid, 
                    'client_name'=>htmlspecialchars($client_name), 
                    'time'=>date('Y-m-d H:i:s'),
                    'is_entry'=>$is_entry,
                );
                
                //Gateway::sendToGroup($room_id, json_encode($new_message));    //往组发推送
                Gateway::joinGroup($client_id, $room_id);

               //self::get_pk_user2();

                // 给当前用户发送用户列表 
                $new_message['client_list'] = $clients_list;
                Gateway::sendToCurrentClient(json_encode($new_message));
                return;
                
            // 客户端发言 message: {type:say, to_client_id:xx, content:xx}
			case 'send_msg':
				$room_id = !empty($message_data['room_id'])?$message_data['room_id']:$_SESSION['room_id'];
				$client_name = $_SESSION['client_name'];
				$client_uid = $message_data['client_uid'];//2018-02-07 10:37:51
				if($message_data['msg_type']=='1'){
					$msg = $message_data['content'];//'发送文本'.
				}elseif($message_data['msg_type']=='2'){//img
					$msg = $message_data['content'];
				}elseif($message_data['msg_type']=='3'){//上传结果
                    $msg = $message_data['content'];
                }

                $new_message = array(
                    'action'=>'send_msg', 
                    'msg_type'=>$message_data['msg_type'], 
                    'from_client_id'=>$client_id,
                    'client_uid'=>$client_uid,
                    'from_client_name' =>$client_name,
                    'to_client_id'=>'all',
                    'content'=>$msg,
                    'room_id'=>$room_id,
                    'time'=>date('Y-m-d H:i:s'),
                );
                //Gateway::bindUid($client_id, $client_uid);//将client_id 和 uid绑定
//Gateway::sendToCurrentClient(json_encode($new_message));
//

//return Gateway::sendToUid($client_uid,json_encode($new_message));
                return Gateway::sendToGroup($room_id ,json_encode($new_message));

            case 'say':
                // 非法请求
                if(!isset($_SESSION['room_id']))
                {
                    throw new \Exception("\$_SESSION['room_id'] not set. client_ip:{$_SERVER['REMOTE_ADDR']}");
                }
                $room_id = $_SESSION['room_id'];
                $client_name = $_SESSION['client_name'];
                
                // 私聊
                if($message_data['to_client_id'] != 'all')
                {
                    $new_message = array(
                        'action'=>'say',
                        'from_client_id'=>$client_id, 
                        'from_client_name' =>$client_name,
                        'to_client_id'=>$message_data['to_client_id'],
                        'content'=>"<b>对你说: </b>".nl2br(htmlspecialchars($message_data['content'])),
                        'time'=>date('Y-m-d H:i:s'),
                    );
                    Gateway::sendToClient($message_data['to_client_id'], json_encode($new_message));
                    $new_message['content'] = "<b>你对".htmlspecialchars($message_data['to_client_name'])."说: </b>".nl2br(htmlspecialchars($message_data['content']));
                    return Gateway::sendToCurrentClient(json_encode($new_message));
                }
                
                $new_message = array(
                    'action'=>'say', 
                    'from_client_id'=>$client_id,
                    'from_client_name' =>$client_name,
                    'to_client_id'=>'all',
                    'content'=>nl2br(htmlspecialchars($message_data['content'])),
                    'time'=>date('Y-m-d H:i:s'),
                );
                return Gateway::sendToGroup($room_id ,json_encode($new_message));
        }
   }
   
   /**
    * 当客户端断开连接时
    * @param integer $client_id 客户端id
    */
   public static function onClose($client_id)
   {
       // debug
       echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']}  client_id:$client_id onClose:''\n";
       
       //Gateway::closeClient($client_id);//踢掉某个客户端2018-03-15 16:08:16
       // 从房间的客户端列表中删除
       if(isset($_SESSION['room_id']))
       {
           $room_id = $_SESSION['room_id'];
           $user_info = Gateway::getSession($client_id);
            
           $new_message = array('action'=>'logout', 'from_client_id'=>$client_id, 'from_client_name'=>$user_info['display_name'], 'time'=>date('Y-m-d H:i:s'));
           Gateway::sendToGroup($room_id, json_encode($new_message));
       }
   }

    //随机抽取用户数据
   public static function get_pk_user($arr,$client_id){
        if(in_array($client_id,$arr)){//去除自己
            array_splice($arr,array_search($client_id,$arr),1);
        }
        $u_key = array_rand(array_filter($arr));
        $to_client_uid = !empty($arr[$u_key])?$arr[$u_key]:0;
        $room_id = $_SESSION['room_id'];
        $aa = 0;
        if(!empty($to_client_uid)){
            $lock_status = task_lock($to_client_uid,'match_user_lock');//
            $room_all_user = Gateway::getClientSessionsByGroup($room_id);
            if($lock_status==false){//重抽
                $aa = '====================';
                $to_client_uid = 0 ;
                return $to_client_uid;
                //return Events::get_pk_user(array_keys($room_all_user),$client_id);
            }
            $time = date('Y-m-d H:i:s',time());
$room_all_user = Gateway::getClientSessionsByGroup($room_id);
            echo "====================time:{$time} client:room_all_user_{$room_id}:".var_export($room_all_user,true). "client_id:{$client_id}33333333333333333333333{$aa}{$to_client_uid} \n";
            if(!empty($client_id))Gateway::leaveGroup($client_id,$room_id);
            if(!empty($to_client_uid))Gateway::leaveGroup($to_client_uid,$room_id);//匹配成功后将对战用户踢出当前房间，防止重复抽取

            return $to_client_uid;
        }else{//没有匹配
            return $to_client_uid;
        }
    }

    //随机抽取用户数据
   public static function get_pk_user2($room_all_user,$client_ids){
        if(empty($_SESSION['room_id']))return;
        $room_id = $_SESSION['room_id'];
        $grad_id = $room_id;//房间段位id
        
        foreach ($room_all_user as $client_key => $row) {
            $client_ids[] = $client_key;
                
            if(count($client_ids)==2){
               //$client_ids = [];//清空
                $client_id = $client_ids[0];
                $to_client_uid = $client_ids[1];

                $from_client_info = Gateway::getSession($client_id);
                $to_client_info = Gateway::getSession($to_client_uid);
                if(empty($to_client_info))$to_client_info = [];

                if(!empty($from_client_info) && !empty($to_client_info)){//匹配成功后，离开该段位房间
                    Gateway::leaveGroup($client_id,$room_id);
                    Gateway::leaveGroup($to_client_uid,$room_id);
                    //进入用户对战房间
                    $room_id =$_SESSION['room_id']= md5($client_id.$to_client_uid);
                    Gateway::joinGroup($client_id, $room_id);
                    Gateway::joinGroup($to_client_uid, $room_id);
                }

                $new_message = [
                    'action'=>'match_succ',
                    'client_uid'=>$from_client_info['openid'],
                    'match_status'=>($from_client_info && $to_client_info) ? 1:0,//1为匹配成功
                    'from_client_info'=>$from_client_info,
                    'to_client_info'=>$to_client_info,
                    'room_id'=>$room_id,//pk房间id
                    'aaaaaaa'=>Gateway::getClientSessionsByGroup($room_id),
                    'bbbbbb'=>$room_all_user
                ];
                if($new_message['match_status']==1){
                    $QuestionsModel = \think\Loader::model('QuestionsModel');
                    $params = [
                        'user_id'=>$from_client_info['id'],
                        'to_user_id'=>$to_client_info['id'],
                        'grad_id'=>$grad_id
                    ];
                    $QuestionsModel->deduct_points($params);//扣除用户参赛段位金币
                    //
                    $params = [
                        'is_auto_answer'=>0,
                        'grad_id'=>$grad_id,
                        'user_id'=>$from_client_info['id'],
                        'to_user_id'=>$to_client_info['id']
                    ];

                    $new_message['questions'] = $QuestionsModel->getQuestionsPk($params);


                    $room_all_user = Gateway::getClientSessionsByGroup(1);
            echo "==================== client:room_all_user_{$room_id}:".var_export($room_all_user,true). "\n";


                    return Gateway::sendToGroup($room_id,json_encode($new_message));
                    //return Timer::del($timer_id);
                    //向对方用户发消息指令
                    //return Gateway::sendToClient($to_client_uid,json_encode($new_message));
                }
                return Gateway::sendToClient($client_id,json_encode($new_message));

            }else{
                //$client_ids[] = $client_key;
                echo "Timer run  ".json_encode($client_ids)."\n";
                //continue;
            }
           
        }
        

    }

    //计划任务执行
    public static function onWorkerStart($task){

        // 每2.5秒执行一次
            $time_interval = 5;
            // 计数
            $count = 1;
            $client_ids = [];
            // 要想$timer_id能正确传递到回调函数内部，$timer_id前面必须加地址符 &
            $timer_id = Timer::add($time_interval, function()use(&$timer_id, &$count,&$client_ids){
                
                if(!empty($_SESSION['room_id'])){
                    $room_id =$_SESSION['room_id'];
                    $room_all_user = Gateway::getClientSessionsByGroup($room_id);

                    if(is_numeric($room_id) && $room_all_user)self::get_pk_user2($room_all_user,$client_ids);

                }

                //echo "Timer run  \n";
                // 运行10次后销毁当前定时器
                /*if($count++ >= 10){
                    echo "Timer::del($timer_id)\n";
                    Timer::del($timer_id);
                }*/
            });

            //检查是否有过期活动 定时器
            // 每2.5秒执行一次
            $time_interval = 3600;
            // 计数
            $count = 1;
            $timer_id2 = Timer::add($time_interval, function()use(&$timer_id, &$count){
                \think\Loader::model('SortModel')->season_ranking();
            });

    }

    //获取好友对战
    public static function get_friends_pk_user($room_id,$user_id,$to_user_id){
        //$is_online = Gateway::isUidOnline($to_user_id);
        //if(empty($is_online))\think\Cache::set($room_id.'is_entry','');
        $from_client_info = [];
        $to_client_info = [];

        $user_info = db('user')->field('id,openid,avatar,display_name,sex,city,grad_name,count_wins,exp,is_robot')->where('openid','IN',[$user_id,$to_user_id])->order("field(openid,'$user_id','$to_user_id')")->select();
echo "==================== client:111111111111111111111111{$room_id}:".var_export($user_info,true). "\n";
        if(!empty($user_info[0])){
            $from_client_info = $user_info[0];
            $from_client_info['room_id'] = $room_id;
            $from_client_info['client_name'] = $user_info[0]['display_name'];
            $from_client_info['level'] = get_user_level($user_info[0]['exp']);
        }
        if(!empty($user_info[1])){    
            //
            $to_client_info = $user_info[1];
            $to_client_info['room_id'] = $room_id;
            $to_client_info['client_name'] = $user_info[1]['display_name'];
            $to_client_info['level'] = get_user_level($user_info[1]['exp']);

        }

        return ['from_client_info'=>$from_client_info,'to_client_info'=>$to_client_info];
    }

    //是否清除是pk用户
    public static function clear_entry_user($client_id,$room_id){
        $user_info = Gateway::getSession($client_id);
        $is_entry = \think\Cache::get($room_id.'is_entry');
        if(!empty($user_info['openid']) && $is_entry==$user_info['openid']){
            \think\Cache::set($room_id.'is_entry','');
        }
    }
  
}
